﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Runtime.InteropServices;
using System.Windows;
using System.Windows.Input;
using System.Windows.Interop;

namespace Douban.Core.HotKeys
{
    public static class HotKey
    {
        private const int WM_HOTKEY = 0x0312;
        private static IDictionary<int, HotKeyTriggeredEventHandler> _hotKeyHandlers;

        static HotKey()
        {
            _hotKeyHandlers = new Dictionary<int, HotKeyTriggeredEventHandler>();
        }

        [DllImport("user32.dll")]
        private static extern bool RegisterHotKey(IntPtr hwnd, int id, uint keyModifiers, uint virtualKey);

        [DllImport("user32.dll")]
        private static extern bool UnregisterHotKey(IntPtr hwnd, int id);

        public static bool Register(Window window, int hotKeyId, HotKeyTriggeredEventHandler handler, ModifierKeys keyModifiers, Key virtualKey)
        {
            if(handler == null)
                throw new ArgumentNullException("handler");

            WindowInteropHelper interopHelper = new WindowInteropHelper(window);
            bool success = RegisterHotKey(
                interopHelper.Handle, hotKeyId, (uint)keyModifiers, (uint)KeyInterop.VirtualKeyFromKey(virtualKey));

            if (success)
            {
                HwndSource source = PresentationSource.FromVisual(window) as HwndSource;
                if (source == null) return false;
                source.AddHook(WndProc);
                _hotKeyHandlers[hotKeyId] = handler;
            }

            return success;
        }

        public static bool Unregister(Window window, int hotKeyId)
        {
            bool success = UnregisterHotKey(new WindowInteropHelper(window).Handle, hotKeyId);
            if (success)
            {
                HwndSource source = PresentationSource.FromVisual(window) as HwndSource;
                source.RemoveHook(WndProc);
                if(_hotKeyHandlers.ContainsKey(hotKeyId))
                    _hotKeyHandlers.Remove(hotKeyId);
            }
            return success;
        }

        public static IntPtr WndProc(IntPtr hwnd, int message, IntPtr wParam, IntPtr lParam, ref bool handle)
        {

            if (message == WM_HOTKEY)
            {
                int hotKeyId = wParam.ToInt32();
                HotKeyTriggeredEventHandler handler;
                if (_hotKeyHandlers.TryGetValue(hotKeyId, out handler))
                    handler(new HotKeyTriggeredEventArgs(hotKeyId));
            }

            return IntPtr.Zero;
        }
    }
}
